package com.fantastic.common.utils;

import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * @author wangl
 * @date 2021/7/7
 *
 * JWT的三个组成部分
 * header (base64后的)
 * payload (base64后的)
 * secret (这个部分需要base64加密后的header和base64加密后的payload
 *         使用"."连接组成的字符串，然后通过header中声明的加密方式进行加密，
 *         然后就构成了jwt的第三部分）
 */
@Slf4j
public class JwtUtils {
    /**
     * 密钥，用于signature（签名）部分解密
     */
    private static final String KEY = "nf-it";
    /**
     * 签发者
     */
    private static final String ISS = "edu.nf";

    /**
     * 生成token
     *
     * @param claims
     * @param ttl 单位秒
     * @return
     */
    public static String createToken(Map<String, Object> claims, long ttl) {
        JwtBuilder builder = Jwts.builder()
                //获取签名秘钥，并采用HS512算法对JWT进行的签名
                .signWith(SignatureAlgorithm.HS512, KEY)
                //jwt唯一标识
                .setId(UUID.randomUUID().toString())
                //设置需要签署的内容
                .setClaims(claims)
                //设置发证人
                .setIssuer(ISS)
                //主题
                .setSubject("JWT_AUTH")
                //签名时间
                .setIssuedAt(new Date());
        //过期时间
        if (ttl >= 0) {
            builder.setExpiration(getExpDate(ttl));
        }
        return builder.compact();
    }

    /**
     * 创建token过期时间
     *
     * @param ttl
     * @return
     */
    private static Date getExpDate(long ttl) {
        Date expDate = new Date(System.currentTimeMillis() + ttl);
        log.info("Token过期时间：" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(expDate));
        return expDate;
    }

    /**
     * 获取载体内容
     *
     * @param token
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T getPayload(String token, String key, Class<T> type) {
        return Jwts.parser()
                .setSigningKey(KEY)
                .parseClaimsJws(token)
                .getBody()
                .get(key, type);
    }

    /**
     * 验证token的有效性
     * 当验证不通过时会抛出相关的异常
     * @param token
     */
    public static void verify(String token) {
        Jwts.parser().setSigningKey(KEY).parseClaimsJws(token);
    }
}
